package com.xhwl.data.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhwl.common.dto.cent.sdata.AreaDTO;
import com.xhwl.common.dto.cent.sdata.PublicAreaDTO;
import com.xhwl.common.dto.cent.sdata.space.ErrorSpace;
import com.xhwl.common.enums.OperationTypeEnum;
import com.xhwl.common.enums.OrganizationTypeEnum;
import com.xhwl.common.exception.DataException;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.*;
import com.xhwl.common.query.cent.sdata.OrganizationQuery;
import com.xhwl.common.query.cent.sdata.PublicAreaQuery;
import com.xhwl.common.utils.StringUtils;
import com.xhwl.data.dao.IOrganizationDao;
import com.xhwl.data.dao.IPublicAreaDao;
import com.xhwl.data.pojo.annotation.OrganizationHandle;
import com.xhwl.data.service.IOrganizationService;
import com.xhwl.data.service.IPublicAreaService;
import com.xhwl.data.util.AutoCodeUtils;
import com.xhwl.data.util.CodePrefixConstant;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: luyi
 * @Description:
 * @Date: Create in 9:45 2021/4/14
 */
@Service
public class PublicAreaServiceImpl extends ServiceImpl<IPublicAreaDao, PublicArea> implements IPublicAreaService {

    @Autowired
    private IPublicAreaDao publicAreaDao;

    @Autowired
    private IOrganizationService organizationService;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private IOrganizationDao organizationDao;

    private static final Logger log = LoggerFactory.getLogger(PublicAreaServiceImpl.class);

    @Override
    @Transactional
    @OrganizationHandle(operationType = OperationTypeEnum.CREATE)
    public ResultJson create(PublicAreaDTO publicAreaDTO) {
        this.save(publicAreaDTO);

        // 生成编码
        if (StringUtils.isEmpty(publicAreaDTO.getCode())) {
            String code = AutoCodeUtils.codeFormat(CodePrefixConstant.PUBLIC_AREA_PREFIX, publicAreaDTO.getId(), CodePrefixConstant.CODE_LENGTH);
            publicAreaDTO.setCode(code);
            publicAreaDao.updateById(publicAreaDTO);
        }
        Organization org = organizationService.getById(publicAreaDTO.getOrganizationId());
        org.setCode(publicAreaDTO.getCode());
        organizationService.update(org);
        return ResultJson.success();
    }

    @Override
    public ResultJson update(PublicAreaDTO publicAreaDTO) {

        PublicArea old = publicAreaDao.selectById(publicAreaDTO.getId());
        if (null == old) {
            log.error("需要更新的楼栋 {} 信息不存在", publicAreaDTO.getId());
            return ResultJson.fail("数据错误");
        }
        Organization organization = organizationService.getById(old.getOrganizationId());
        organization.setName(publicAreaDTO.getName());
        organization.setSortField(publicAreaDTO.getSortField());
        if (StringUtils.isNotEmpty(publicAreaDTO.getCode())) {
            organization.setCode(publicAreaDTO.getCode());
        }
        if (null != publicAreaDTO.getParentId()) {
            organization.setParentId(publicAreaDTO.getParentId());
        }
        if (null != old.getSortField() && !old.getSortField().equals(publicAreaDTO.getSortField())){
            List<Organization> organizationList = organizationService.list(new OrganizationQuery().withParentId(organization.getParentId()));
            List<Integer> orgIds = organizationList.stream().filter(i->null != i.getSortField()).map(Organization::getId).collect(Collectors.toList());
            UpdateWrapper<PublicArea> updateWrapper = new UpdateWrapper<>();
            updateWrapper.in("organization_id",orgIds);
            UpdateWrapper<Organization> organizationUpdateWrapper = new UpdateWrapper<>();
            organizationUpdateWrapper.in("id",orgIds);
            if (old.getSortField() > publicAreaDTO.getSortField()){
                //大改小 小于等于'大'并且大于等于'小'的加1
                updateWrapper.ge("sort_field",publicAreaDTO.getSortField());
                updateWrapper.le("sort_field",old.getSortField());
                organizationUpdateWrapper.ge("sort_field",publicAreaDTO.getSortField());
                organizationUpdateWrapper.le("sort_field",old.getSortField());
                updateWrapper.setSql("sort_field = sort_field+1");
                organizationUpdateWrapper.setSql("sort_field = sort_field+1");
            }else {
                //小改大 大于'小'并且小于等于'大'的减1
                updateWrapper.le("sort_field",publicAreaDTO.getSortField());
                updateWrapper.gt("sort_field",old.getSortField());
                organizationUpdateWrapper.le("sort_field",publicAreaDTO.getSortField());
                organizationUpdateWrapper.gt("sort_field",old.getSortField());
                updateWrapper.setSql("sort_field = sort_field-1");
                organizationUpdateWrapper.setSql("sort_field = sort_field-1");
            }
            this.update(updateWrapper);
            organizationService.update(organizationUpdateWrapper);
        }
        ResultJson update = organizationService.update(organization);
        if (!update.getState()) {
            return update;
        }

        boolean b = this.updateById(publicAreaDTO);
        return b ? ResultJson.success() : ResultJson.fail("数据错误");
    }

    @Override
    public Page<PublicArea> page(PublicAreaQuery publicAreaQuery, Page page) {
        return publicAreaDao.page(page, publicAreaQuery);
    }

    @Override
    public List<PublicArea> list(PublicAreaQuery publicAreaQuery) {
        return publicAreaDao.list(publicAreaQuery);
    }

    @Override
    @Transactional
    public ResultJson delete(Integer id) {
        PublicArea publicArea = publicAreaDao.selectById(id);
        if (null == publicArea) {
            return ResultJson.fail("数据错误");
        }
        Boolean aBoolean = organizationService.hasChild(publicArea.getOrganizationId());
        if (aBoolean) {
            return ResultJson.fail("存在子节点无法删除");
        }
        boolean i1 = organizationService.removeById(publicArea.getOrganizationId());
        int i = publicAreaDao.deleteById(id);
        if (0 == i || !i1) {
            return ResultJson.fail("数据错误");
        }
        return ResultJson.success("删除成功");
    }

    @Override
    @Transactional
    public ResultJson batchCreate(List<PublicAreaDTO> publicAreaDTOs) {

        if (publicAreaDTOs.isEmpty()) {
            return ResultJson.success();
        }
        IPublicAreaService bean = applicationContext.getBean(IPublicAreaService.class);
        for (PublicAreaDTO publicAreaDTO : publicAreaDTOs) {
            bean.create(publicAreaDTO);
        }
        return ResultJson.success(publicAreaDTOs);
    }

    /**
     * @param publicAreaDTOs
     * @return
     */
    public ResultJson batchCreateFaster(List<PublicAreaDTO> publicAreaDTOs) {
        if (CollectionUtils.isEmpty(publicAreaDTOs)) {
            return ResultJson.fail("无效的数据");
        }

        List<ErrorSpace> errors = new ArrayList<>();
        // 数据处理 1 分组 2 校验
        Set<Integer> collect = publicAreaDTOs.stream().map(i -> i.getParentId()).collect(Collectors.toSet());
        Map<Integer, List<PublicAreaDTO>> parentAndChildMap = new HashMap<>();
        for (Integer i : collect) {
            parentAndChildMap.put(i, publicAreaDTOs.stream().filter(j -> i.equals(j.getParentId())).collect(Collectors.toList()));
        }
        for (Map.Entry<Integer, List<PublicAreaDTO>> entry : parentAndChildMap.entrySet()) {
            Integer parentId = entry.getKey();
            Organization organization = organizationDao.selectById(parentId);

            // 上级信息校验
            if (null == organization) {
                for (PublicAreaDTO publicAreaDTO : entry.getValue()) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("上级信息不存在");
                    errorSpace.setObj(publicAreaDTO);
                    errors.add(errorSpace);
                }
                continue;
            }

            // 名称校验
            List<PublicAreaDTO> value = entry.getValue();
            Map<String, PublicAreaDTO> map = new HashMap<>();
            Map<String, PublicArea> publicAreaDB = new HashMap<>();
            QueryWrapper<Organization> organizationQueryWrapper = new QueryWrapper<>();
            organizationQueryWrapper.select("name");
            organizationQueryWrapper.eq("parent_id", entry.getKey());
            List<Organization> areaOrg = organizationDao.selectList(organizationQueryWrapper);
            if (!areaOrg.isEmpty()) {
                for (Organization area : areaOrg) {
                    publicAreaDB.put(area.getName(), null);
                }
            }
            for (PublicAreaDTO publicAreaDTO : value) {
                if (publicAreaDB.containsKey(publicAreaDTO.getName()) || map.containsKey(publicAreaDTO.getName())) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("名称重复");
                    errorSpace.setObj(publicAreaDTO);
                    errors.add(errorSpace);
                } else {
                    map.put(publicAreaDTO.getName(), publicAreaDTO);
                }
            }
            List<PublicArea> correctList = new ArrayList<>();
            for (Map.Entry<String, PublicAreaDTO> entry1 : map.entrySet()) {
                correctList.add(entry1.getValue());
            }

            // code 校验
            Map<String, PublicAreaDTO> codeMap = new HashMap<>();
            Map<String, Object> codeMapDB = new HashMap<>();
            // 这里仅校验同一个项目下的编码重复
            QueryWrapper<Organization> organizationQueryWrapper1 = new QueryWrapper<>();
            organizationQueryWrapper1.select("code");
            organizationQueryWrapper1.eq("project_id", organization.getProjectId());
            organizationQueryWrapper1.eq("type", OrganizationTypeEnum.AREA.id);
            List<Organization> organizations1 = organizationDao.selectList(organizationQueryWrapper1);
            if (!organizations1.isEmpty()) {
                codeMapDB = organizations1.stream().collect(Collectors.toMap(Organization::getCode, Organization::getCode));
            }
            for (PublicAreaDTO publicAreaDTO : value) {
                if (!StringUtils.isEmpty(publicAreaDTO.getCode()) && (codeMapDB.containsKey(publicAreaDTO.getCode()) || codeMap.containsKey(publicAreaDTO.getCode()))) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("编码重复");
                    errorSpace.setObj(publicAreaDTO);
                    errors.add(errorSpace);
                } else {
                    codeMap.put(publicAreaDTO.getName(), publicAreaDTO);
                }
            }
            correctList = correctList.stream().filter(i -> codeMap.containsKey(i.getName())).collect(Collectors.toList());

            if (correctList.isEmpty()) {
                log.info("校验后没有合适的数据");
                continue;
            }
            try {
                this.saveBatch(correctList);
            } catch (Exception e) {
                log.error("批量保存失败 {}", e.getMessage());
                for (PublicArea area : correctList) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("批量保存失败");
                    errorSpace.setObj(area);
                    errors.add(errorSpace);
                }
                continue;
            }
            // 保存组织信息
            List<Organization> organizations = new ArrayList<>();
            for (PublicArea area : correctList) {
                Organization organization1 = new Organization();
                organization1.setName(area.getName());
                organization1.setParentId(area.getParentId());
                if (StringUtils.isEmpty(area.getCode())) {
                    String code = AutoCodeUtils.codeFormat(CodePrefixConstant.PUBLIC_AREA_PREFIX, area.getId(), CodePrefixConstant.CODE_LENGTH);
                    area.setCode(code);
                }
                organization1.setSortField(area.getSortField());
                organization1.setCode(area.getCode());
                organization1.setType(OrganizationTypeEnum.PUBLIC_AREA.id.intValue());
                organization1.setLevel(organization.getLevel() + 1);
                organization1.setIndustryId(organization.getIndustryId());
                organization1.setEnterpriseId(organization.getEnterpriseId());
                if (null != organization.getProjectId()) {
                    organization1.setProjectId(organization.getProjectId());
                }
                organizations.add(organization1);
            }
            organizationService.saveBatch(organizations);

            // 统一分组下名称不会重复
            Map<String, Integer> collect1 = organizations.stream().collect(Collectors.toMap(Organization::getName, Organization::getId));

            for (PublicArea area : correctList) {
                area.setOrganizationId(collect1.get(area.getName()));
            }
            this.updateBatchById(correctList);
        }
        return ResultJson.success(errors);
    }

    @Override
    public String getCurrentCode() {
        return UUID.randomUUID().toString();
    }

    @Override
    public ResultJson refreshSort(PublicAreaQuery publicAreaQuery) {
        List<PublicArea> publicAreas = this.list(publicAreaQuery);
        List<Organization> organizationList = organizationService.list(new OrganizationQuery().withIds(publicAreas.stream().map(PublicArea::getOrganizationId).collect(Collectors.toList())));
        organizationList = organizationList.stream().distinct().collect(Collectors.toList());
        Map<Integer,Organization> organizationMap = organizationList.stream().collect(Collectors.toMap(Organization::getId, Function.identity()));
//        List<List<Area>> parts = Lists.partition(areas, 500);
        for (int i = 0; i < publicAreas.size(); i++) {
            publicAreas.get(i).setSortField(i+1);
            JSONObject jsonObject = JSONObject.parseObject(publicAreas.get(i).getExpand());
            if (null != jsonObject){
                jsonObject.put("sortField",i+1);
                publicAreas.get(i).setExpand(jsonObject.toJSONString());
            }
            organizationMap.get(publicAreas.get(i).getOrganizationId()).setSortField(i+1);
        }
        this.updateBatchById(publicAreas);
        organizationService.updateBatchById(organizationMap.values());
        return ResultJson.success("刷新成功");
    }
}
